package cn.com.zcode.core.cxf;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletConfig;

import org.apache.cxf.endpoint.Server;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.message.Message;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
import org.apache.log4j.Logger;

import cn.com.zcode.core.scan.ScanFilter;
import cn.com.zcode.core.scan.Scanner;

/**
 * Auto publish the class for web service which has @ annotation
 * 
 * @author zeng.jinqing
 * @date Apr 19, 2013
 */
public class AutoPublishServlet extends CXFNonSpringServlet {
	private Logger logger = Logger.getLogger(AutoPublishServlet.class);
	private static final long serialVersionUID = 1L;
	private boolean debug = false;
	private String scanPackages = "scanPackages";
	private String classFilter = "classFilter";
	private ScanFilter<Class<?>> filter = null;
	public static Map<String, Type[]> serverinfo = null;

	@SuppressWarnings("unchecked")
	@Override
	protected void loadBus(ServletConfig sc) {
		super.loadBus(sc);
		this.scanPackages = sc.getInitParameter("scanPackages");
		this.classFilter = sc.getInitParameter("classFilter");
		String debugstr = sc.getInitParameter("debug");
		this.debug = debugstr != null && "true".equals(debugstr.trim().toLowerCase());
		if (scanPackages != null && !scanPackages.isEmpty()) {
			filter = loadFilter(classFilter);
			Scanner scanner = new Scanner();
			Set<Class<?>> set = scanner.scan(filter, scanPackages.split(","));
			for (Class<?> pclass : set) {
				AutoPublish publishAddress = (AutoPublish) pclass.getAnnotation(AutoPublish.class);
				String address = publishAddress.value();
				logger.info("Publishing web Service :" + pclass + " -> " + address);
				this.publish(pclass, address);

			}
		}

	}

	private void publish(Class<?> pclass, String address) {
		try {
			JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
			svrFactory.setServiceClass(pclass);
			svrFactory.setAddress(address);
			svrFactory.setServiceBean(pclass.newInstance());
			if (this.debug) {
				List<Interceptor<? extends Message>> inters = svrFactory.getOutInterceptors();
				inters.add(new LoggingOutInterceptor());
				inters.add(new LoggingInInterceptor());
			}
			Server server = svrFactory.create();
			if (this.debug) {
				if (serverinfo == null) {
					serverinfo = new HashMap<String, Type[]>();
				}
				Method[] method = pclass.getMethods();
				String serverName = server.getEndpoint().getService().getName() + "";
				for (Method m : method) {
					String name = m.getName();
					Type[] paramTypeList = m.getGenericParameterTypes();
					serverinfo.put(serverName + "." + name, paramTypeList);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
		}
	}

	
	private ScanFilter<Class<?>> loadFilter(String classFilter) {
		ScanFilter<Class<?>> filter = null;
		if (classFilter != null) {
			try {
				@SuppressWarnings("unchecked")
				Class<? extends ScanFilter<Class<?>>> fclass = (Class<? extends ScanFilter<Class<?>>>) Class.forName(classFilter);
				filter = fclass.newInstance();
			} catch (Exception e) {
				e.printStackTrace();
				logger.error(e);
			}
		}
		if (filter == null) {
			logger.warn("Publish ClassFilter is Empty,Load DefaultPublishClassFilter!");
			filter = new DefaultPublishClassFilter();

		}
		return filter;
	}

}